import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import drawingObjects.DrawingObject;
import drawingObjects.FreeFormLine;
import drawingObjects.Oval;
import drawingObjects.Rectangle;
import drawingObjects.Text;
import drawingObjects.Triangle;

import javax.imageio.ImageIO;
import javax.swing.*;

public class CourierCanvas extends JPanel implements ActionListener, KeyListener{

	/**
	 * 
	 */
	private static final long serialVersionUID = -4889341102596999123L;
	private ArrayList<ArrayList<DrawingObject>> pages;
	private int pageIndex = 0;
	private ArrayList<DrawingObject> drawingObjects;
	private DrawingObject currentObject;
	private Image background;
	public CourierButtonPanel buttonPanel;
	
	public CourierCanvas(){
		try {
			background = ImageIO.read(new File("src/images/background.jpg"));
		} catch (IOException e) {
			e.printStackTrace();
		}
		this.setLayout(new BorderLayout());
		this.setPreferredSize(new Dimension(600,600));
		//this.setMinimumSize(new Dimension(675,750));
		//this.setMaximumSize(new Dimension(600,600));
		pages = new ArrayList<ArrayList<DrawingObject>>();
		drawingObjects = new ArrayList<DrawingObject>();
		pages.add(drawingObjects);
		CanvasMouseAdapter mouseListener = new CanvasMouseAdapter(this);
		addMouseListener(mouseListener);
		addMouseMotionListener(mouseListener);
		newCurrentObject();
		this.addKeyListener(this);
		this.font = new Font("Serif", Font.PLAIN, fontSize);
	}
	
	protected void deletePage() {
		if(pages.size() > 1){
			pages.remove(pageIndex);
			if(pageIndex > 0)
				pageIndex--;
			drawingObjects = pages.get(pageIndex);
		}
		else
			drawingObjects.clear();
		newCurrentObject();
		repaint();
	}
	
	protected void newPage() {
		if(pageIndex < pages.size() - 1){ //insert the page rather than append
			pages.add(pageIndex+1, new ArrayList<DrawingObject>());			
		}
		else{ //append the page
			pages.add(new ArrayList<DrawingObject>());
		}
		pageIndex++;
		drawingObjects = pages.get(pageIndex);
		repaint();
	}
	
	protected void forward() {
		if(pageIndex < pages.size() - 1)
			pageIndex++;
		drawingObjects = pages.get(pageIndex);
		repaint();
	}
	
	protected void backward() {
		if(pageIndex > 0)
			pageIndex--;
		drawingObjects = pages.get(pageIndex);
		repaint();
	}
	
	String currentType = "freeform";
	//handles radio button clicks of different object types
	@Override
	public void actionPerformed(ActionEvent e) {
		if(currentObject != null)commit();
		String cmd = e.getActionCommand();
		currentType = cmd;
		if(cmd == "freeform"){
			currentObject = new FreeFormLine();
		}
		else if(cmd == "rectangle"){
			currentObject = new Rectangle();
		}
		else if(cmd == "oval"){
			currentObject = new Oval();
		}
		else if(cmd == "text"){
			currentObject = new Text(fontSize);
		}
		else if(cmd == "triangle"){
			currentObject = new Triangle();
		}
		currentObject.color = selectedColor;
		currentObject.stroke = strokeSize;
	}
	
	private void newCurrentObject(){
		drawStarted = false;
		String cmd = currentType;
		if(cmd == "freeform"){
			currentObject = new FreeFormLine();
		}
		else if(cmd == "rectangle"){
			currentObject = new Rectangle();
		}
		else if(cmd == "oval"){
			currentObject = new Oval();
		}
		else if(cmd == "text"){
			currentObject = new Text(fontSize);
		}
		else if(cmd == "triangle"){
			currentObject = new Triangle();
		}
		currentObject.color = selectedColor;
		currentObject.stroke = strokeSize;
	}
	
	public void undo() {
		if(drawStarted){
			newCurrentObject();
			this.repaint();
			return;
		}
			
		if(drawingObjects.size() > 1)
			drawingObjects.remove(drawingObjects.size() -1);
		else
			drawingObjects.clear();
		this.repaint();
	}
	
	private boolean drawStarted = false;
	public void startDraw(Point p){
		if(!hasFocus()) { requestFocus(); }
		currentObject.start(p);
		drawStarted = true;
		this.repaint();
	}
	
	public void stepDraw(Point p){
		drawStarted = true;
		currentObject.step(p);
		this.repaint();
	}
	
	public void commit(){
		if(currentObject.commit()){
			if(!drawingObjects.contains(currentObject))
				addComponent(currentObject);
			this.repaint();
			newCurrentObject();
		}
	}
	
	public void addComponent(DrawingObject d){
		drawingObjects.add(d);
	}
	
	private int fontSize = 12;
	private Font font;
	public void setFontSize(int size){
		this.fontSize = size;
		this.font = new Font("Serif", Font.PLAIN, fontSize);
		if(currentType == "text")
			((Text)currentObject).fontSize = fontSize;
		repaint();
	}
	
	private Color selectedColor = Color.black;
	public void setColor(Color c){
		this.selectedColor = c;
		currentObject.color = c;
		repaint();
	}
	
	private int strokeSize = 1;
	public void setStrokeSize(int size){
		this.strokeSize = size;
		currentObject.stroke = this.strokeSize;
		repaint();
	}
	
	public void paintComponent(Graphics g){
		//super.paintComponent(g);
		Graphics2D g2 = (Graphics2D)g;
		this.getGraphics().setFont(font);
		this.getGraphics().setColor(Color.black);
		g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
		        RenderingHints.VALUE_ANTIALIAS_ON);
		g2.drawImage(background, 0, 0, getWidth(), getHeight(), null);
		for(DrawingObject c : drawingObjects){
			c.paintComponent(g2);
		}
		currentObject.paintComponent(g2);
		if(buttonPanel != null)
			buttonPanel.repaint();
	}
	
	public int getPageIndex() {
		return this.pageIndex;
	}

	@Override
	public void keyPressed(KeyEvent e) {}

	@Override
	public void keyReleased(KeyEvent e) {
		if(currentType == "text"){
			((Text)currentObject).step(e);
			this.repaint();
		}
	}
	@Override
	public void keyTyped(KeyEvent e) {}
}

 class CanvasMouseAdapter extends MouseAdapter implements MouseMotionListener{
	private CourierCanvas canvas;
	private boolean dragStart = false;
	public CanvasMouseAdapter(CourierCanvas c) { 
		this.canvas = c;
	}
	public void mousePressed(MouseEvent e) { 
		//System.out.println("mouse pressed: "+e.getPoint().x+", "+e.getPoint().y);
		canvas.startDraw(e.getPoint());
	} 
	@Override
	public void mouseDragged(MouseEvent e) {
		if(!dragStart){
			canvas.startDraw(e.getPoint());
			dragStart = true;
		}
		else
			canvas.stepDraw(e.getPoint());
		//System.out.println("mouse dragged: "+e.getPoint().x+", "+e.getPoint().y);
	}
	@Override
	public void mouseReleased(MouseEvent e){
		canvas.commit();
		dragStart = false;
	}
 }
